<template>
	<view class="__pd_virtual_list">
		<scroll-view 
			type='list'
			scroll-y="true"
			:lower-threshold='200'
			:upper-threshold="200"
			enhanced
			:show-scrollbar='false'
			@scrolltoupper="toUpper"
			@scrolltolower="toLower"
			@scroll='scrollHandler'>
			<slot :render-list='renderList'></slot>
		</scroll-view>
	</view>
</template>

<script lang="ts" setup>
import PD from '../libs';
import type { ScrollViewScrollRes } from '../libs/wx-types';

const props = withDefaults(defineProps<{
	height ?: number, //scrollView高度，单位px
	data : Array<unknown>, //数据源
	max ?: number, //最多渲染多少条数据
	step ?: number, //向下滑动时，每次回滚多少条数据
	isLoading : boolean, //是否正在加载数据
}>(), {
	height : PD.UniHelp.getSystemInfo().windowHeight,
	data : () => [],
	max : 30,
	step : 10,
	isLoading : false,
});

const scrollViewHeight = computed(() => props.height + 'px');
const scrollView = ref();
interface EmitType {
	(e: 'touch-lower') : void;//上拉触底
};
const emits = defineEmits<EmitType>();
const startIndex = ref(0);
const endIndex = ref(startIndex.value + props.max);
const renderList = computed(() => {
	const v = props.data.slice(startIndex.value, endIndex.value);
	return v;
});

//有新数据新增进来，尝试更新下标
watch(() => props.data, (n, o) => {
	if (n.length > o.length && o.length !== 0 && n.length >= props.max) { //新增数据
		const diff = n.length - o.length;
		startIndex.value += diff;
		endIndex.value += diff;
		return;
	};
});


//上拉触底
const toLower = () => {
	//下标突破了源数据的最大数量，尝试更新下标，并通知加载更多数据
	if (endIndex.value >= props.data.length || startIndex.value >= props.data.length) {
		if (props.isLoading) return;//防止多次触发
		emits('touch-lower');
		return;
	};
	//如果没突破源数据的最大数量，则还是在当前源数据内进行渲染
	startIndex.value += props.step;
	endIndex.value += props.step;
};

const toUpper = () => {
	if (startIndex.value <= 0) {
		wx.pageScrollTo({
			scrollTop : 0,
		});
	};
	if (props.data.length <= props.max) return; //数据源长度未达到最大size，不更新下标
	if (startIndex.value <= 0) {//起始下标突破0，当做0处理
		startIndex.value = 0;
		endIndex.value = startIndex.value + props.max;
		return;
	};
	//正常回滚更新下标
	startIndex.value = startIndex.value - props.step <= 0 ? 0 : startIndex.value - props.step;
	endIndex.value = startIndex.value + props.max;
};

const scrollHandler = (e : ScrollViewScrollRes) => {
	if (e.detail.deltaY < 0 && Math.abs(e.detail.deltaY) >= 10) {
		wx.pageScrollTo({
			scrollTop : PD.UniHelp.getSystemInfo().windowHeight,
			duration : 300
		});
		return;
	};

	if (e.detail.deltaY >= 0 && e.detail.scrollTop === 0) {
		wx.pageScrollTo({
			scrollTop : 0,
			duration : 300
		});
	};
};

/**
 * 更新下标，主要用于解决watch data 解决不了的场景，由业务方自行决定是否调用
 * @param {number} 开始下标
 */
const updateIndex = (newStartIndex : number ) => {
	startIndex.value = newStartIndex;
	endIndex.value = startIndex.value + props.max;
};


defineExpose({
	updateIndex, 
});

</script>

<style lang="less">
.__pd_virtual_list {
	scroll-view {
		height: v-bind(scrollViewHeight);
	}
}
</style>